package service

import (
	"fmt"
	"math/rand/v2"
	"smart-flow/monitor/config"
	"smart-flow/monitor/proto"
	"time"
)

func RandomBlockCount() int64 {
	return config.BlockMinCount + rand.Int64N(config.BlockDelta+1) // 发送20MB~50MB数据
}

func RandomStat() string {
	statIps := config.PusherEndpointsInfo.StatIps
	ip := statIps[rand.IntN(len(statIps))]
	return fmt.Sprintf("[%s]:%d", ip, config.UdpStatPort)
}

func RandomSpeed(v6Reachable int) string {
	var containers []*proto.ContainerInfo
	if v6Reachable == 0 {
		containers = ContainersInstance().GetAllV4Containers()
	} else {
		containers = ContainersInstance().GetAllV6Containers()
	}
	ip := containers[rand.IntN(len(containers))].ContainerIp
	return fmt.Sprintf("http://[%s]:%d%s", ip, config.HttpStreamPort, config.PathStream)
}

func RandomAddress(v6Reachable int) ([]string, []string, []string) {
	var containers []*proto.ContainerInfo
	if v6Reachable == 0 {
		containers = ContainersInstance().GetRandomV4Containers(config.AppConfig().Dy.AgentMaxEndpoint)
	} else {
		containers = ContainersInstance().GetRandomV6Containers(config.AppConfig().Dy.AgentMaxEndpoint)
	}
	var tcpAddresses, udpAddresses, httpUrls []string
	if config.AppConfig().Dy.TcpProportion > 0 && len(containers) > 0 {
		tcpAddresses = randomTcpAddresses(containers)
	}
	if config.AppConfig().Dy.UdpProportion > 0 && len(containers) > 0 {
		udpAddresses = randomUdpAddresses(containers)
	}
	if config.AppConfig().Dy.HttpProportion > 0 && len(containers) > 0 {
		httpUrls = randomHttpUrls(containers)
	}
	return tcpAddresses, udpAddresses, httpUrls
}

func randomTcpAddresses(containers []*proto.ContainerInfo) []string {
	var addresses []string
	for _, container := range containers {
		addresses = append(addresses, fmt.Sprintf("[%s]:%d", container.ContainerIp, config.TcpPortStartPos+rand.IntN(config.TcpPortCount)))
	}
	length := len(addresses)
	if length <= config.PerUseMinCount {
		return addresses
	}
	rand.Shuffle(length, func(i, j int) {
		addresses[i], addresses[j] = addresses[j], addresses[i]
	})
	return addresses
}

func randomUdpAddresses(containers []*proto.ContainerInfo) []string {
	var addresses []string
	for _, container := range containers {
		addresses = append(addresses, fmt.Sprintf("[%s]:%d", container.ContainerIp, config.UdpPortStartPos+rand.IntN(config.UdpPortCount)))
	}
	length := len(addresses)
	if length <= config.PerUseMinCount {
		return addresses
	}
	rand.Shuffle(length, func(i, j int) {
		addresses[i], addresses[j] = addresses[j], addresses[i]
	})
	return addresses
}

func randomHttpUrls(containers []*proto.ContainerInfo) []string {
	var httpUrls []string
	for _, container := range containers {
		httpUrls = append(httpUrls, fmt.Sprintf("http://[%s]:%d%s", container.ContainerIp, config.HttpStreamPort, config.PathStream))
	}
	length := len(httpUrls)
	if length <= config.PerUseMinCount {
		return httpUrls
	}
	rand.Shuffle(length, func(i, j int) {
		httpUrls[i], httpUrls[j] = httpUrls[j], httpUrls[i]
	})
	return httpUrls
}

// nolint: unused
func randomPorts(ports []int) int {
	return ports[rand.IntN(len(ports))]
}

func CalcRateLimit(bandwidth, agentRateLimit int64) (int64, int64, int64, int) {
	if bandwidth <= config.MB/4 || agentRateLimit <= 0 { // 带宽小于2M，放弃
		return 0, 0, 0, 0
	}
	tcpProportion := config.AppConfig().Dy.TcpProportion
	udpProportion := config.AppConfig().Dy.UdpProportion
	httpProportion := config.AppConfig().Dy.HttpProportion
	totalProportion := tcpProportion + udpProportion + httpProportion
	if totalProportion == 0 {
		return 0, 0, 0, 0
	}
	available := min(bandwidth*config.Byte2Bit/config.KBit/4, agentRateLimit, config.MaxRateLimit) // 1/4带宽不超过人为限速和系统限速(Kbps)
	perUseCount := max(config.PerUseMinCount, int(available/config.KBit/2))
	tcpRateLimit := available * tcpProportion / totalProportion
	if tcpRateLimit > 0 {
		tcpRateLimit++
	}
	udpRateLimit := available * udpProportion / totalProportion
	if udpRateLimit > 0 {
		udpRateLimit++
	}
	httpRateLimit := available * httpProportion / totalProportion
	if httpRateLimit > 0 {
		httpRateLimit++
	}
	return tcpRateLimit, udpRateLimit, httpRateLimit, perUseCount
}

func CalcBeRunning(duration int64) int {
	now := time.Now()
	year, month, day := now.Date()
	startTime := time.Date(year, month, day, 19, 30, 0, 0, now.Location()) // 19:30
	endTime := time.Date(year, month, day, 22, 10, 0, 0, now.Location())   // 22:10
	if now.After(endTime) {
		return 0
	}
	if now.After(startTime) && now.Before(endTime) {
		return 1
	}
	if now.Before(startTime) {
		futureTime := now.Add(time.Duration(duration) * time.Minute)
		if futureTime.After(startTime) { // 运行时间区间包含开始时间
			return 1
		}
		startOfDay := time.Date(year, month, day, 0, 0, 0, 0, now.Location())
		minutesPassed := int(now.Sub(startOfDay).Minutes())
		if rand.IntN(config.AppConfig().Dy.PusherProportion) < minutesPassed { // 有概率运行，概率=当天已经过去的分钟数/PusherProportion
			return 1
		}
	}
	return 0
}
